#include "devaccuator.h"
#include <map>
#include <sstream>
#include "QLogTool.h"

using namespace std;

namespace {
    constexpr size_t MAX_PTS = 128;
}

void DevAccuator::ConfigCmdHandle()
{
    m_exeTable[ADC_CALIB]  = [this](const uint8_t *data, size_t len) { return MstSetCalib(data, len);   };
    m_exeTable[ADC_REPORT] = [this](const uint8_t *data, size_t len) { return RecvAdcReport(data, len); };
}

int DevAccuator::MstEchoDump(const uint8_t *data, size_t len)
{
    if (data == nullptr || len != sizeof (FrmDumpMeasure)) {
        return ERR_FRMEERR;
    }
    const FrmDumpMeasure* dump = reinterpret_cast<const FrmDumpMeasure*>(data);
    LOG("[0x%08x-0x%08x-0x%08x] Reporting", dump->id.UUID[0], dump->id.UUID[1], dump->id.UUID[2]);
    map<int32_t, int32_t> calibPts;
    for (size_t idx = 0; idx < ADC_CALIBPTS_MAX; idx++) {
        auto p = dump->caliber[ADC_CHANNEL_VOLT].pts[idx];
        calibPts[p.x] = p.y;
    }
    ostringstream ss;
    for (auto o : calibPts) {
        ss << o.first << "|" << o.second << "; ";
    }
    LOG("ADC_CHANNEL_VLOT:　" + ss.str());
    memcpy(&m_dump, data, len);
    m_isUpdated = true;

    return ERR_SUCCESS;
}

static bool isPtsEqual(const dataPt &a, const dataPt&b)
{
    return a.x == b.x && a.y == b.y;
}

static bool isPtsGreater(const dataPt &a, const dataPt&b)
{
    return a.x > b.x;
}

void DevAccuator::SlotSetCurrData(uint32_t ch, double val)
{
    FrmAdcCalib frm;
    memcpy(&frm, &(m_dump.caliber[ch]), sizeof(frm));
    // 基于当前设备参数表做增量更新
    vector<dataPt> pts(m_dump.caliber[ch].pts, m_dump.caliber[ch].pts + ADC_CALIBPTS_MAX);
    std::sort(pts.begin(), pts.end(), isPtsGreater);
    pts.erase(unique(pts.begin(), pts.end(), isPtsEqual), pts.end()); // 去重
    while (pts.size() < 8) {
        pts.push_back(pts.back());
    }
    while (pts.size() > 8) {
        pts.erase(pts.begin());
    }
    int32_t rawX = (ch == ADC_CHANNEL_VOLT ? GetVoltageRaw() : GetCurrentRaw());
    int32_t rawY = static_cast<int32_t>(val / ADC_VAL_SCALE);
    pts.push_back({rawX, rawY});
    pts.erase(pts.begin());
    std::sort(pts.begin(), pts.end(), isPtsGreater);
    // 增量更新完毕，构造帧
    for(size_t idx = 0; idx < ADC_CALIBPTS_MAX; idx++) {
        frm.pts[idx] = pts[idx];
        LOG("%u, %u", pts[idx].x, pts[idx].y);
    }
    LOG("Fix channel[%u] Point '%f' to '%f'", ch, GetVoltageVal(), val);
    AddTask(ADC_CALIB, &frm, sizeof(frm));
}

int DevAccuator::MstSetCalib(const uint8_t *data, size_t len)
{
    TxPkg(ADC_CALIB, data, len);
    LOG("MstSetCalib");
    return ERR_SUCCESS;
}

int DevAccuator::RecvAdcReport(const uint8_t* data, size_t len)
{
    if (data == nullptr || len != sizeof (FrmAdcReport)) {
        return ERR_FRMEERR;
    }
    const FrmAdcReport* pkg = reinterpret_cast<const FrmAdcReport*>(data);
    size_t chnlIdx = pkg->channel;
    if (chnlIdx > ADC_CHANNEL_VOLT) {
        return ERR_FRMEERR;
    }
    lock_guard<mutex> lk(m_dataLock);
    m_slvReport[chnlIdx].rawVal = pkg->rawVal;
    m_slvReport[chnlIdx].result = pkg->result;

    m_curveRaw[chnlIdx].push_back(GetVoltageRaw());
    m_curveVal[chnlIdx].push_back(GetVoltageVal());
    if (m_curveRaw[chnlIdx].size() >= curvePtsMax) {
        m_curveRaw[chnlIdx].pop_front();
        m_curveVal[chnlIdx].pop_front();
    }
    return ERR_SUCCESS;
}
